
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * assign1.c
 * Copyright (C) Michael 2008 <mikey.mockos@gmail.com>
 * 
 * assign1.c is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * assign1.c is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <glib.h>
#include <gtk/gtk.h>

#include <opencv/cv.h>
#include <opencv/highgui.h>

#include <math.h>
#include <stdlib.h>

/* GTK vars*/
GtkWidget* frame = 0;
GtkWidget *panel0 = 0, *panel1 = 0, *panel2 = 0, *panel3 = 0;
GtkWidget *separator0 = 0, *separator1 = 0, *separator2 = 0;

GtkWidget *table0 = 0, *table1 = 0, *table2 = 0;

GtkWidget *button0 = 0, *button1 = 0, *button2 = 0, *button3 = 0, *button4 = 0, 
*saveButton1 = 0, *saveButton2 = 0, *contRotate = 0, *interpol = 0, *replic = 0;

GtkWidget *field0 = 0, *field1 = 0, *field2 = 0, *field3 = 0, *field4 = 0, 
*field5 = 0;

GtkWidget *label0 = 0, *label1 = 0, *label2 = 0, *label3 = 0, *label4 = 0, 
*label5 = 0, *label6, *label7;

GtkWidget *radio = 0;
GSList *group;

GtkWidget *filew;

/* openCV vars */
const char *name = "Original Image", *name2 = "Result Image";
IplImage *img = 0, *img2 = 0;


static void loadImage (GtkWidget*, GtkFileSelection* fs);

static void fileChoose (GtkWidget *widget, gpointer data) {
	
	/* File selector */
	filew = gtk_file_selection_new ("File selection");
	/* Connect the ok_button to file_ok_sel function */
    g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filew)->ok_button), "clicked", 
					            G_CALLBACK (loadImage), (gpointer) filew);
    
    /* Connect the cancel_button to destroy the widget */
    g_signal_connect_swapped (G_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button),
	                          "clicked", G_CALLBACK (gtk_widget_destroy),
			                  G_OBJECT (filew));
	gtk_widget_show (filew);
}	

/* Load image */
static void loadImage(GtkWidget* w, GtkFileSelection* fs) {
	
    gchar* fileName = gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs));
   
    if(fileName)
	    img = cvLoadImage (fileName, 3);
	
	if(!img) 
	    printf("Could not load image file: %s \n", fileName);
	
	else {	
		gtk_widget_destroy(filew);
		cvShowImage(name, img);
	}	
	
	return;
}

/* Save image */
static void savePNG (GtkWidget *widget, gpointer data) {
	
	if(!img2) 
	    printf("No image loaded.\n");
	
	else {
	//	IplImage* img3 = cvCloneImage (img2);
	//	cvCvtColor(img2, img3, CV_GRAY2BGR);
		
		if(!cvSaveImage("Result.png",img2)) 
		    printf("Could not save: Result.png\n");
	}	
	
	return;
}

/* Save image */
static void saveJPG (GtkWidget *widget, gpointer data) {
	
	if(!img2) 
	    printf("No image loaded.\n");
	
	else
		if(!cvSaveImage("Result.JPG",img2)) 
		    printf("Could not save: Result.jpg\n");	
	
	return;
}

/* Negate image */
static void negateImage (GtkWidget *widget, gpointer data) {
    
	if(!img)
		printf("No image is loaded\n");
	
	else {		
		img2 = cvCloneImage (img); 
		
		int w = img2 -> width;
        int h = img2 -> height;
        int step = img2 -> widthStep;
        int channels = img2 -> nChannels;
        char *data = img2 -> imageData;

        int i,j,k;
        for (i = 0; i < w; i++) {
            for (j = 0; j < h; j++) {
                for (k = 0; k < channels; k++) {
                    int pos = i * step + j * channels + k;
                    data[pos] = 255 - data[pos];
                }
            }
        }
		cvShowImage(name2, img2);
	}	
    return;
}

/* Rotation */
static void rotateImage (GtkWidget *widget, gpointer data) {
	
	if(!img)
		printf("No image is loaded.\n");
	
	else {
		short X, Y, angle;

        X = atoi (gtk_entry_get_text (GTK_ENTRY (field0)));
	    Y = atoi (gtk_entry_get_text (GTK_ENTRY (field1)));
	    angle = atoi (gtk_entry_get_text (GTK_ENTRY (field2)));
	
	    img2 = cvCloneImage (img);
	
	    float m[6];
		/* Constructing the marix */
        CvMat M = cvMat (2, 3, CV_32F, m);
		
        m[0] = (float)(cos(angle * CV_PI/180.0));
        m[1] = (float)(sin(angle * CV_PI/180.0));
        m[2] = (float)X;
        m[3] = -m[1];
        m[4] = m[0];
        m[5] = (float)Y;
	
	    /* Applying the transformations */
	    cvGetQuadrangleSubPix (img, img2, &M);
		
		//img = cvCloneImage (img2);
	    cvShowImage (name2, img2);
	}	
}

static void rotateImageCont (GtkWidget *widget, gpointer data) {

	if(!img)
		printf("No image is loaded.\n");
	
	else {
		short X, Y, angle;

        X = atoi (gtk_entry_get_text (GTK_ENTRY (field0)));
	    Y = atoi (gtk_entry_get_text (GTK_ENTRY (field1)));
	    angle = atoi (gtk_entry_get_text (GTK_ENTRY (field2)));
	
	    img2 = cvCloneImage (img);
		
		float m[6];
        double factor;
        CvMat M;

		while(1) {
			factor = (cos(angle*CV_PI/180.) + 1.1) * 3;
			M = cvMat (2, 3, CV_32F, m);
			
            m[0] = (float)(factor*cos(-angle*2*CV_PI/180.));
            m[1] = (float)(factor*sin(-angle*2*CV_PI/180.));
            m[2] = X;
            m[3] = -m[1];
            m[4] = m[0];
            m[5] = Y;
			
            cvGetQuadrangleSubPix(img, img2, &M);
	        cvShowImage (name2, img2);
            
			if(cvWaitKey(5) == 27 )
                break;
            
			angle = ((angle + 1) % 360);
        }
	}
}

/* Scaling */
static void scaleImage (GtkWidget *widget, gpointer data) {
	
	if(!img)
		printf("No image is loaded.\n");
	
	else {
	//	img2 = cvCloneImage (img);
		short X, Y;
		
        X = atoi (gtk_entry_get_text (GTK_ENTRY (field4)));
	    Y = atoi (gtk_entry_get_text (GTK_ENTRY (field5)));
	
		/* Creating an image with the targeted dimentions and resizing the original to be identical */
	    img2 = cvCreateImage (cvSize(X, Y), IPL_DEPTH_8U, (img->nChannels));
	    cvResize (img, img2, CV_INTER_LINEAR);
	
	    cvShowImage (name2, img2);
	}	
}

/* Scaling by interpolation */
static void scaleImage1 (GtkWidget *widget, gpointer data) {
	
	if(!img)
		printf("No image is loaded.\n");
	
	else {
		short scale;
        scale = atoi (gtk_entry_get_text (GTK_ENTRY (field3)));
	
		/* Creating an image with the targeted dimentions and resizing the original to be identical */
	    img2 = cvCreateImage (cvSize((img->height) * scale, (img->width) * scale), IPL_DEPTH_8U, (img->nChannels));
		
		/* Interpolations */
		cvResize (img, img2, CV_INTER_LINEAR);
	
	    cvShowImage (name2, img2);
	}	
}

/* Scaling by replication (MANUAL) */
static void scaleImage2 (GtkWidget *widget, gpointer data) {
	
	if(!img)
		printf("No image is loaded.\n");
	
	else {
		short scale;
        scale = atoi (gtk_entry_get_text (GTK_ENTRY (field3)));
	
		/* Creating an image with the targeted dimentions and resizing the original to be identical */
	    img2 = cvCreateImage (cvSize((img->height) * scale, (img->width) * scale), IPL_DEPTH_8U, (img->nChannels));
		
		/* Replication (MANUAL) */
	//	img2 = cvCloneImage (img); 
		
		int w = img -> width;
        int h = img -> height;
        int step = img -> widthStep;
        int channels = img -> nChannels;
        char *data = img -> imageData;

        int i,j, x, y;
		CvScalar s, s2;
		
        for (i = 0; i < w; i++) {
            for (j = 0; j < h; j++) {
                s = cvGet2D(img, i, j); // get the (i,j) pixel value
				
				for(x = scale * i; x < (scale * (i + 1)); x++) {
					
					for(y = scale * j; y < (scale * (j + 1)); y++) {
					    s2 = cvGet2D(img2, x, y);
						s2.val[0] = s.val[0];
						s2.val[1] = s.val[1];
						s2.val[2] = s.val[2];
						cvSet2D(img2, x, y, s2);		
					}
				}	
            }
        }
		cvShowImage (name2, img2);
    }
}

/* Termination */
static gboolean terminate (GtkWidget* widget, GdkEvent* event, gpointer data) {
	
	cvReleaseImage (&img);
	cvDestroyWindow (name);
	cvDestroyWindow (name2);
    
	gtk_main_quit ();
    return FALSE;
}

/* Main */
int main (int argc, char* argv[]) {

    gtk_init (&argc, &argv);

    /* Create a new window */
    frame = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	//gtk_widget_set_size_request (GTK_WIDGET (frame), 200, 300);
    gtk_window_set_title (GTK_WINDOW (frame), "Image Manipulator");
    g_signal_connect (G_OBJECT (frame), "delete_event", G_CALLBACK (terminate), NULL);

    gtk_container_set_border_width (GTK_CONTAINER (frame), 20);
	
    /* Panel 1 */
	panel0 = gtk_vbox_new (FALSE, 5);
	gtk_container_add (GTK_CONTAINER (frame), panel0);
	
    button0 = gtk_button_new_with_label ("Load Image");
    g_signal_connect (G_OBJECT (button0), "clicked", G_CALLBACK (fileChoose), (gpointer) "cameraman.bmp");
    gtk_box_pack_start (GTK_BOX(panel0), button0, FALSE, FALSE, 5);
//	gtk_table_attach_defaults (GTK_TABLE (buttonsTable), button0, 0, 1, 0, 1);
    gtk_widget_show (button0);
	
	saveButton1 = gtk_button_new_with_label ("Save PNG");
    g_signal_connect (G_OBJECT (saveButton1), "clicked", G_CALLBACK (savePNG), (gpointer) "cameraman.bmp");
	gtk_box_pack_start (GTK_BOX(panel0), saveButton1, FALSE, FALSE, 5);
	gtk_widget_show (saveButton1);
	
	saveButton2 = gtk_button_new_with_label ("Save JPG");
    g_signal_connect (G_OBJECT (saveButton2), "clicked", G_CALLBACK (saveJPG), (gpointer) "cameraman.bmp");
	gtk_box_pack_start (GTK_BOX(panel0), saveButton2, FALSE, FALSE, 5);
	gtk_widget_show (saveButton2);
	
    button1 = gtk_button_new_with_label ("Negate Image");
    g_signal_connect (G_OBJECT (button1), "clicked", G_CALLBACK (negateImage), (gpointer) "Negate Image");
    gtk_box_pack_start (GTK_BOX(panel0), button1, FALSE, FALSE, 0);
//	gtk_table_attach_defaults (GTK_TABLE (buttonsTable), button1, 0, 1, 2, 3);
    gtk_widget_show (button1);
	
	separator0 = gtk_hseparator_new ();
	gtk_box_pack_start (GTK_BOX(panel0), separator0, FALSE, FALSE, 5);
	gtk_widget_show (separator0);
	
	/* Panel 2 */
	panel1 = gtk_hbox_new (FALSE, 5);
	gtk_container_set_border_width (GTK_CONTAINER (panel1), 10);
	gtk_container_add (GTK_CONTAINER (panel0), panel1);
	
	table0 = gtk_table_new (3, 3, FALSE);
    gtk_container_add (GTK_CONTAINER (panel0), table0);
	
	label0 = gtk_label_new ("X");
	gtk_table_attach_defaults (GTK_TABLE (table0), label0, 0, 1, 0, 1);
	gtk_widget_show (label0);
	
	label1 = gtk_label_new ("Y");
	gtk_table_attach_defaults (GTK_TABLE (table0), label1, 0, 1, 1, 2);
	gtk_widget_show (label1);
	
	label2 = gtk_label_new ("Angle");
	gtk_table_attach_defaults (GTK_TABLE (table0), label2, 0, 1, 2, 3);
	gtk_widget_show (label2);
	
	field0 = gtk_entry_new ();
	gtk_entry_set_max_length (GTK_ENTRY (field0), 5);
	gtk_table_attach_defaults (GTK_TABLE (table0), field0, 1, 2, 0, 1);
	gtk_widget_show (field0);
	
	field1 = gtk_entry_new ();
	gtk_entry_set_max_length (GTK_ENTRY (field1), 5);
	gtk_table_attach_defaults (GTK_TABLE (table0), field1, 1, 2, 1, 2);
	gtk_widget_show (field1);
	
	field2 = gtk_entry_new ();
	gtk_entry_set_max_length (GTK_ENTRY (field2), 5);
	gtk_table_attach_defaults (GTK_TABLE (table0), field2, 1, 2, 2, 3);
	gtk_widget_show (field2);
	
//	gtk_box_pack_start (GTK_BOX (panel1), table0, FALSE, FALSE, 0);
	gtk_widget_show (table0);
    
	button2 = gtk_button_new_with_label ("Rotate");
    g_signal_connect (G_OBJECT (button2), "clicked", G_CALLBACK (rotateImage), (gpointer) "Rotate");
    gtk_table_attach_defaults (GTK_TABLE (table0), button2, 2, 3, 2, 3);
    gtk_widget_show (button2);
	
	contRotate = gtk_button_new_with_label ("Continuous Rotation");
    g_signal_connect (G_OBJECT (contRotate), "clicked", G_CALLBACK (rotateImageCont), (gpointer) "RotateCont");
    gtk_table_attach_defaults (GTK_TABLE (table0), contRotate, 2, 3, 1, 2);
    gtk_widget_show (contRotate);
	
	separator1 = gtk_hseparator_new ();
	gtk_box_pack_start (GTK_BOX(panel0), separator1, FALSE, FALSE, 5);
	gtk_widget_show (separator1);
	
	/* Panel 3 */
	panel2 = gtk_hbox_new (FALSE, 5);
	gtk_container_set_border_width (GTK_CONTAINER (panel2), 10);
	gtk_container_add (GTK_CONTAINER (panel0), panel2);
	
	table1 = gtk_table_new (3, 3, FALSE);
    gtk_container_add (GTK_CONTAINER (panel2), table1);
	
	label5 = gtk_label_new ("Factor");
	gtk_table_attach_defaults (GTK_TABLE (table1), label5, 0, 1, 2, 3);
	gtk_widget_show (label5);
	
	interpol = gtk_button_new_with_label ("Interpolation");
    g_signal_connect (G_OBJECT (interpol), "clicked", G_CALLBACK (scaleImage1), (gpointer) "Interpolation");
    gtk_table_attach_defaults (GTK_TABLE (table1), interpol, 1, 2, 0, 1);
    gtk_widget_show (interpol);
	
	replic = gtk_button_new_with_label ("Replication");
    g_signal_connect (G_OBJECT (replic), "clicked", G_CALLBACK (scaleImage2), (gpointer) "Replication");
    gtk_table_attach_defaults (GTK_TABLE (table1), replic, 1, 2, 1, 2);
    gtk_widget_show (replic);
	
//	radio = gtk_radio_button_new_with_label (NULL, "Interpolation");
//  gtk_table_attach_defaults (GTK_TABLE (table1), radio, 1, 2, 0, 1);
//  gtk_widget_show (radio);

//	group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio));
//  radio = gtk_radio_button_new_with_label (group, "Replication");
//  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
//  gtk_table_attach_defaults (GTK_TABLE (table1), radio, 1, 2, 1, 2);
//  gtk_widget_show (radio);	
	
	field3 = gtk_entry_new ();
	gtk_entry_set_max_length (GTK_ENTRY (field3), 1);
	gtk_table_attach_defaults (GTK_TABLE (table1), field3, 1, 2, 2, 3);
	gtk_widget_show (field3);
	
	//gtk_box_pack_start (GTK_BOX (panel2), table1, FALSE, FALSE, 0);
	gtk_widget_show (table1);
	
	separator2 = gtk_hseparator_new ();
	gtk_box_pack_start (GTK_BOX(panel0), separator2, FALSE, FALSE, 5);
	gtk_widget_show (separator2);
	
	/* Panel 4 */
	panel3 = gtk_hbox_new (FALSE, 5);
	gtk_container_set_border_width (GTK_CONTAINER (panel3), 10);
	gtk_container_add (GTK_CONTAINER (panel0), panel3);
	
	table2 = gtk_table_new (3, 3, FALSE);
    gtk_container_add (GTK_CONTAINER (panel3), table2);
	
	label6 = gtk_label_new ("X");
	gtk_table_attach_defaults (GTK_TABLE (table2), label6, 0, 1, 0, 1);
	gtk_widget_show (label6);
	
	label7 = gtk_label_new ("Y");
	gtk_table_attach_defaults (GTK_TABLE (table2), label7, 0, 1, 1, 2);
	gtk_widget_show (label7);
	
	field4 = gtk_entry_new ();
	gtk_entry_set_max_length (GTK_ENTRY (field4), 5);
	gtk_table_attach_defaults (GTK_TABLE (table2), field4, 1, 2, 0, 1);
	gtk_widget_show (field4);
	
	field5 = gtk_entry_new ();
	gtk_entry_set_max_length (GTK_ENTRY (field5), 5);
	gtk_table_attach_defaults (GTK_TABLE (table2), field5, 1, 2, 1, 2);
	gtk_widget_show (field5);
	
//	gtk_box_pack_start (GTK_BOX (panel3), table2, FALSE, FALSE, 0);
	gtk_widget_show (table2);
    
	button4 = gtk_button_new_with_label ("Scale");
    g_signal_connect (G_OBJECT (button4), "clicked", G_CALLBACK (scaleImage), (gpointer) "Scale");
    gtk_table_attach_defaults (GTK_TABLE (table2), button4, 2, 3, 1, 2);
    gtk_widget_show (button4);
	
	
    gtk_widget_show (panel0);
	gtk_widget_show (panel1);
	gtk_widget_show (panel2);
	gtk_widget_show (panel3);
    gtk_widget_show (frame);
	
	/* openCV frame */
	cvNamedWindow(name, 6);
	cvNamedWindow(name2, 6);

    gtk_main ();

    return 0;
}

